--[[
    桌子基类

--]]
local skynet = require("skynet")
local utils = require("utils")
local util = require("util")
local reason = require("reason")
local error_code = require("error_code")
local constant = require("constant")
local cjson = require "cjson"
local math_abs = math.abs
local math_floor = math.floor
local table_insert = table.insert 
local table_remove = table.remove 


local DeskBase = class("DeskBase")

--注意父类的变量只是说明， 在子类必需要有对应的变量
function DeskBase:ctor()
    --父类的变量不要初始化
	self.state_time_handler = nil --定时器句柄
	self.timer = nil --定时器
    self.state_time = nil --各个游戏状态的时间
    self.service_closed = nil --服务已关闭

    --百人场用到的-------------------
    self.bead = {
        win_id = nil, --1闲 2和 3庄
        pair_id = nil, --1无 2闲对 3庄对
    }
    self.win_pool_list = {} --赢的id历史记录列表 存放 self.bead 对象
    self.caishen_coins_map = {} --财神中每人可赢的钱

    -------------------

end

--状态定时器
function DeskBase:setTimer(time, callback, loop, param)
    -- print("_________定时器没设置时间____5555_____1")
	if not time then
		--没设置时间
		dbglog("___定时器没设置时间___")		
		return 
	end	
	if self.state_time_handler then 
		self.timer:unregister(self.state_time_handler)
		self.state_time_handler = nil	
	end
	self.state_time_handler = self.timer:register(time, callback, loop, param)	
end

--关闭定时器
function DeskBase:stopTimer()
	if self.state_time_handler then 
		self.timer:unregister(self.state_time_handler)
		self.state_time_handler = nil	
	end
end

function DeskBase:getAllStateTime()
    local time_list = {}
    local time = 0
    for k, v in pairs(self.state_list) do 
        time = self.state_time[v[1]] 
        table.insert(time_list, time)
    end
    return time_list
end

--状态初始时间
function DeskBase:getStateTime(state)
    local state = state or self:getState()
    if not state then 
        return 0
    end
    return self.state_time[state] or 0
end

--剩余时间
function DeskBase:getLeftTime()
    local left_time = self.timer:leftTime(self.state_time_handler)
	return left_time
end

--给指定玩家发消息
function DeskBase:sendToUser(uid, msg_name, msg)
    local user = self.user_manager:getUser(uid)
    if not msg then 
        dbglog("______sendToUser_________msg为空__",uid, msg_name, msg)
        return        
    end
    if not user then 
        dbglog("______sendToUser_________用户已不在桌子__",uid, msg_name, msg)
        return 
    end
    local fd = user:getFD()
    if not fd or fd <= 0 then
        if fd == -1 then --机器人消息
            global.message_dispatch:dispatchSelfMessage('robot_message', uid, msg_name, msg)
        else
            dbglog("______sendToUser_____uid____无效fd",uid, fd )
        end
        return
    end
    local error_id = msg.result
    if error_id and error_id>0 then 
        local error_des = self.room_config:getErrorInfo(error_id) --错误描述
        -- dbglog("_________msg.description___",error_des, msg.description)
        if not msg.description or msg.description=="" then 
            if error_des then 
                msg.description = error_des
            else
                msg.description = ""            
            end
        end
    end
    return utils.send_to_gateway(0, uid, fd, msg_name, msg)
end

--给别的玩家发消息
--action: proto message name
function DeskBase:sendToOther(action, my_id, msg)
	local user_list = self.user_manager:getUserList()	
	for uid, user in pairs(user_list) do 
		if uid~=my_id then 
            -- print("______action___",uid, action, msg)
			self:sendToUser(uid, action, msg)
		end
	end	
end

--给桌子所有玩家广播消息
function DeskBase:sendToAllUser(action, msg)
	self:sendToOther(action, nil, msg)
end

--给无座玩家发消息
function DeskBase:sendToNoSeat(action, msg)
	local user_list = self.user_manager:getUserList()	
	for uid, user in pairs(user_list) do 
		--判断是否在线
		--判断是否有座位
		if user:seated() then 
			self:sendToUser(uid, action, msg)
		end
	end
end

--给非机器人玩家发消息
function DeskBase:sendToNoRobot(action, msg)
    local user_list = self.user_manager:getUserList()    
    for uid, user in pairs(user_list) do             
        if user:isPlayer() then 
            self:sendToUser(uid, action, msg)
        end
    end
end


--当前状态
function DeskBase:getState()
	return self.fsm:get()
end

--状态对应的数字
function DeskBase:getStateNum()
	local state = self:getState()
	for k, v in pairs(self.state_list) do 
		if state == v[1] then 
			return k
		end
	end
	return 0
end

--当前操作所剩余的时间
function DeskBase:getOperTime()
	local curState = self:getState()
	if not curState or not self.state_time[curState] then 
		return 0
	end
	local time = self.state_time[curState] - (os.time() - self.oper_start_time)
	if time < 0 then 
		time = 0
	end
	return time
end

--清除离线的玩家
function DeskBase:removeDisconnect()
    local user_list = self.user_manager:getUserList()
    local need = false
    for uid, user in pairs(user_list) do         
        if user:getDisconnect() then  
            -- errlog("___2____user:getDisconnect()____", user:getDisconnect())         
            if user:isSeated() then       
                self:sendToAllUser('table.NTF_LEAVE',{uid = uid, reason=0, room_name = self.room_config:getRoomName()})
            end
            self:watchSession(uid, false)
            self:sendUserLeave(uid)              
            self.user_manager:removeUser(uid)            

            if user:isPlayer() then
                R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})        
            end    
            need = true                   
        end
    end
    if need then 
        --通知分配服务器更新桌子状态
        self:ntMatchsvrTableStats()
    end
end

--告诉table_mgr玩家离开
function DeskBase:sendUserLeave(uid)
    local user = self.user_manager:getUser(uid)
    if user:isRobot() then 
        return 
    end    
    skynet.send('.table_mgr','lua','leave',uid)  
    self:realTimeWinLose(user, os.time())
end


--改变桌子状态
function DeskBase:changeState(event)
    self.fsm:fire(event)
    -- skynet.send(skynet.self(), "lua", "robot_desk_state", self.fsm:get())
end

--帐单信息
function DeskBase:getBillInfo(user)
    local t = {
        game_type=self.game_type,
        table_type=self.table_type,
    }
    t.client_version = user:getClientVersion()
    t.channel = user:getChannel()
    t.cur_channel = user:getCurChannel()
    t.device_id = user:getDeviceId()
    t.device_brand = user:getDeviceBrand()
    t.os_system = user:getOsSystem()
    t.platform = user:getPlatform()
    
    return t
end

--操作玩家金币
function DeskBase:addChip(uid, chip, reason)
    local user = self.user_manager:getUser(uid)
    if not user then 
        if uid ~= 1 then 
            errlog("___________addChip__error__", uid, chip, reason)
        end
        return 
    end
    local bill_info = self:getBillInfo(user)
    local is_robot = user:isRobot()
    local server = R().basesvr({key=uid})
    if not is_robot then 
        local ok,succ,ret = server:call('.msg_handler', 'add_coins', uid, chip, reason, {is_robot=is_robot}, bill_info)
        if not ok or not succ then
            errlog(uid,'操作金币失败failed to add coins', ok, succ, chip, user:getCoins(), reason)        
            return false
        end    
        user:setCoins(ret.curr)
        return ret.curr
    end
    user:addCoins(chip)
    return user:getCoins()
end

--减玩家金币
function DeskBase:reduceChip(uid, chip, reason)
    local user = self.user_manager:getUser(uid)
    if not user then 
        if uid ~= 1 then 
            errlog("___________reduceChip__error__", uid, chip, reason)
        end
        return 
    end    
    if chip == 0 then 
        return 
    end
    local bill_info = self:getBillInfo(user)
    local is_robot = user:isRobot()
    local server = R().basesvr({key=uid})
    if not is_robot then     
        local ok,succ,ret = server:call('.msg_handler', 'reduce_coins', uid, chip, reason, {is_robot=is_robot}, bill_info)
        if not ok or not succ then
            errlog(uid,'操作金币失败failed to reduce coins',ok, succ, chip, user:getCoins())        
            return false
        end    
        user:setCoins(ret.curr)
        return ret.curr  
    end    
    user:addCoins(-chip)
    return user:getCoins()
end

--财神中奖结算
function DeskBase:caishenResult(uid, coins, award_coins, ...)
    local user = self.user_manager:getUser(uid)
    local robot = user:isRobot()
    local ok, succ, ret = R().basesvr({key=uid}):call(".msg_handler", "caishen_coins", uid, coins, award_coins, {is_robot=robot},self:getBillInfo(user))
    if not ok then
        errlog(string_format("uid(%d) call basesvr caishen_coins coins error", uid))
        return false
    end
    if not succ then
        errlog(string_format("uid(%d) basesvr caishen_coins coins succ == false error", uid))
        return false
    end
    user:setCoins(ret)
    return ret
end

--增加玩家服务费
function DeskBase:addFreeChip(uid, free_chip, reason)
    if free_chip == 0 then
        return 
    end
    local user = self.user_manager:getUser(uid)
    if not user or user:isRobot() then 
        return 
    end    
    local cur_chip = user:getCoins()
    R().basesvr({key=uid}):send('.msg_handler','add_player_fee_coins',uid, free_chip or 0)
    -- billlog({op="reducecoins", uid = uid, curr = cur_chip,value = free_chip, is_robot = user:isRobot(),r = reason}, self:getBillInfo(user))
    user:addFree(free_chip)
    dbglog("______add_player_fee_coins_________", uid, free_chip, reason)
end

--财神扣钱
function DeskBase:payCaiShenCoins(uid, coins)
    local user = self.user_manager:getUser(uid)
    local caishenjiadao_store = self.room_config:getCaiShenStore()
    local fee_rate = caishenjiadao_store.fee_rate
    local sysback_coins = math_floor((coins *fee_rate) / 10000)
    local base_coins = coins - sysback_coins
    local curr_coins
    --玩家赢的金币
    local award_coins = self.store_manager:checkCaishenStore(uid,coins)
    user:addTotalBet(coins) --总投注
    user:addCurBet(coins)
    local bet_coins = coins --投入
    local win_lose = 0 --输赢
    local produce = 0 --产出
    if award_coins then
        --add_coins
        dbglog("======中财神到加钱======award_coins", award_coins, base_coins)
        curr_coins = self:caishenResult(uid, coins, award_coins)
        if not curr_coins then
            errlog("reduce coins failed",ret )
            self:sendToUser(uid, 'table.RSP_OPEN_CAISHEN',{result = error_code.NOT_ENOUGH_COINS})
            return 
        end          
        user:addWinLose(award_coins-coins) --玩家桌子内总输赢
        user:addProduce(award_coins)
        win_lose = award_coins-coins
        produce = award_coins

        self:sendLoseWinToFriendServer(coins - award_coins)
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self.table_type, uid, base_coins, sysback_coins)
        R().exdbsvr(1):send('.caishen_mgr','sub_caishen_base',self.table_type,uid,award_coins)
    else                
        local ret = self:reduceChip(uid, coins, reason.OPEN_CAISHEN)
        if not ret then
            errlog("reduce coins failed",ret )
            self:sendToUser(uid, 'table.RSP_OPEN_CAISHEN',{result = error_code.NOT_ENOUGH_COINS})
            return
        end
        user:addWinLose(-coins) --玩家桌子内总输赢
        win_lose = -coins
        produce = 0

        self:sendLoseWinToFriendServer(coins)
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self.table_type, uid, base_coins, sysback_coins)
        curr_coins = ret
    end
    
    local bet_coins = coins
    local produce = produce
    local win_lose = win_lose
    local free = 0
    self:sendSummary(uid, bet_coins, produce, win_lose, free)

    self:ntMoneyChangeToHall(uid, curr_coins)
    if user:getSeatId() > 0 then     
        self:sendToAllUser("table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = curr_coins } } })  
    else
        self:sendToUser(uid, "table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = curr_coins } } })   
    end

    --清空中财神
    self:setCaiShenCoins(uid)    
    self:sendToUser(uid, 'table.RSP_OPEN_CAISHEN',{result = 0,award_coins = award_coins})
    return 
end


--失去金币，通知basesvr
function DeskBase:sendLoseCoin(uid, coins)
    --通知redis
    local user = self.user_manager:getUser(uid)
    if not user or user:isRobot() then 
        return 
    end
    local server = R().basesvr({key=uid})
    server:send('.msg_handler', 'add_lose_coins', uid, coins)
end

--金币输赢流水
function DeskBase:loseWinCoins(user, coins)    
    if user:isRobot() then 
        return 
    end    
    local uid = user:getUid()    
    R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins', uid, coins)    
end

--财神检查
function DeskBase:checkCaiShen(user, coins) 
    if not user then 
        return
    end 
    if user:isRobot() then 
        return 
    end    
    -- coins = 1000
    local uid = user:getUid()  
    --赢才会开赌神
    if coins > 0 then
        --添加玩家首冲进度
        -- R().activitysvr(1):send('.activity_mgr','act_add_first_charge_process',uid, coins)
        R().basesvr({key=uid}):send('.msg_handler','add_wining_times',uid, self.game_type)
        --检查是否触发财神驾到            
        if self.store_manager:checkTriggerCaiShenJiaDao(user, coins) then            
            self:ntCaiShenJiaDao(uid, coins)
        end
    elseif coins < 0 then
        R().basesvr({key=uid}):send('.msg_handler','add_losing_times',uid, self.game_type)
    end
end

--把输赢发送到好友服(平台游戏概况)
function DeskBase:sendLoseWinToFriendServer(system_lose_win)           
    if system_lose_win == 0 then 
        return 
    end 
    dbglog("system_lose_win:",system_lose_win)
    R().friendsvr(1):send('.info_mgr', 'set_room_summary', self.table_type, {table_type=self.table_type, lose_win=system_lose_win})
end        

--关服
function DeskBase:setServiceClose(closed)
    errlog("______________服务关闭___________", closed) 
    self.service_closed = closed
end

--每局休息时检查是否关服
function DeskBase:checkServiceClose()
    -- dbglog("__checkServiceClose____",self.room_config:getGameType(), self.room_config:getRoomName(), self.room_config:getOpenGame())
    if not self.room_config:getOpenGame() then --场次开关
        self.service_closed = true
    end
    if not self.service_closed then 
        return 
    end
    local uids = {}
    local user_list = self.user_manager:getUserList()
    for uid, user in pairs(user_list) do 
        if user:isPlayer() then
            self:sendToUser(uid, 'table.RSP_LEAVE', {result=error_code.RSP_SUCESS})                        
            R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})                    
            self:watchSession(uid, false)
        end                    
        skynet.send('.table_mgr','lua', 'leave', uid)
        table_insert(uids, uid)
    end
    self.user_manager:clear()
    self:ntMatchsvrTableStats(true)  --更新桌子
    skynet.send('.table_mgr', 'lua', 'on_table_delete', self.table_id, uids)    --删除状态
    --归还机器人
    if self.robot_manager then 
        self.robot_manager:removeAll()
    end
    --关闭服务
    billlog({op = "close_table", status = self:getStateNum(), password = self_password}) --preload.lua
    dbglog('关闭游戏桌子 now delete this table',self.table_id, self.room_config:getRoomName())
    skynet.exit()    
end


--取输赢记录列表
function DeskBase:getWinPoolList()
    return self.win_pool_list
end

--中财神每人可赢的钱
function DeskBase:getCaiShenCoins(uid)
    return self.caishen_coins_map[uid] or 0
end

function DeskBase:setCaiShenCoins()    
    if not self.caishen_coins_map[uid] then
        return 
    end
    self.caishen_coins_map[uid] = nil
end


--------------------------------------------------------------------------------------------
-- overwrite 
--------------------------------------------------------------------------------------------
--[[
--入桌回调
function DeskBase:enterReqCallback(uid, fd, msg)
    errlog("______需要子游戏重写_____enterReqCallback___")    
end

--离线回调
function DeskBase:disconnectCallback(uid)
    errlog("______需要子游戏重写_____disconnectCallback___")    
end

--离开桌子
function DeskBase:leaveReqCallback(uid)
    errlog("______需要子游戏重写____leaveReqCallback____")    
end

--overwrite
--大厅牌中需要的状态
function DeskBase:getHallStateNum()
    --状态 1修息 2下注 3结算 (每个游戏要自己处理转换)
    --子游戏重写
    errlog("______需要子游戏重写____getHallStateNum____")    
end


--]]





--------------------------------------------------------------------------------------------
--nt message
--------------------------------------------------------------------------------------------

--通知分配服务器更新桌子状态
function DeskBase:ntMatchsvrTableStats(is_delete)
    local table_stats = {}
    if is_delete then
        table_stats.table_gid = self.table_gid
        table_stats.table_type = self.table_type
        R().newmatchsvr(1):send('.table_mgr', 'delete_table_stats', table_stats)
    else
        table_stats.table_type = self.table_type
        table_stats.left_num = self.user_manager:getLeftUserNum()
        table_stats.table_gid = self.table_gid
        table_stats.table_pattern = self.table_pattern
        -- dbglog("__2222222222222____ntMatchsvrTableStats__________", tostring_r(table_stats))
        R().newmatchsvr(1):send('.table_mgr', 'update_table_stats', table_stats)
    end
end

--玩家入桌消息推送
function DeskBase:ntPlayerEnter(uid)
    local user = self.user_manager:getUser(uid)
    local play_effect = false    
    local enter_word = self.room_config:canPlayEffect(user:getVipLevel()) 
    if enter_word then
        play_effect = true
    else
        enter_word = nil
    end
    if user:getBeted() then --下注过就是断线重连
        play_effect = false
    end    
    --入场动画
    local data = {play_effect=play_effect, player=user:getClientInfo(), enter_word=enter_word}
    print("notify_player_enter________",data)
    self:sendToAllUser('table.NTF_PLAYER_ENTER', data)
end

--通知大厅币值改变
--coins玩家身上现有的金币
function DeskBase:ntMoneyChanged(uid, chged, reason)
    local ntf = {}
    local flags = 0
    if chged.coins then --金币改变
        ntf.coins = chged.coins
        flags = flags | (1 << 0)
    end
    if chged.gems then --宝石改变
        ntf.gems = chged.gems
        flags = flags | (1 << 1)
    end
    if chged.roomcards then --房卡改变
        ntf.roomcards = chged.roomcards
        flags = flags | (1 << 2)
    end
    ntf.flags = flags
    ntf.reason = reason
    self:sendToUser(uid, 'hall.NTF_USER_MONEY', ntf)        
end

--币值改变
--coins玩家身上现有的金币
function DeskBase:ntMoneyChangeToUser(uid)    
    local user = self.user_manager:getUser(uid)
    if not user or user:isRobot() then 
        return 
    end    
    self:sendToUser(uid,"table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = user:getCoins() } } }) 
end


--通知大厅币值改变
--coins玩家身上现有的金币
function DeskBase:ntMoneyChangeToHall(uid, coins, money_changed_reason)    
    local user = self.user_manager:getUser(uid)
    if not user or user:isRobot() then 
        return 
    end    
    --这时候不确保玩家是否一定在桌子上，因此需要走大厅去通知金币变化
    R().hallsvr{key=uid}:send('.msg_handler','toagent',uid, 'notify_money_changed',{coins = coins}, money_changed_reason)
end

--通知财神
function DeskBase:ntCaiShenJiaDao(uid, coins)    
    dbglog("=============notify_caishenjiadao", uid, coins)
    local curr_time = util.get_now_time()
    local caishenjiadao = self.room_config:getCaiShenJiaDao()
    local countdown_time = caishenjiadao.countdown_time or 10
    local end_time
    if self.caishen_time then
        end_time = self:caishen_time()
    else
        end_time = curr_time + countdown_time + self:getStateTime("gameover") --把动画时间加上
    end
    self.caishen_coins_map[uid] = coins
    self:sendToUser(uid, 'table.NTF_CAISHENJIADAO', {end_time = end_time, trigger_coins = coins, game_type = self.game_type})
    billlog({op = "caishenjiadao", type = "trigger", uid = uid, table_type = self.table_type, coins = coins})
end








--------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------
--桌子起动与初始化
function DeskBase:start()
	self.user_manager = global.user_manager
	self.room_config = global.room_config
	self.rule = global.rule
    self.robot_manager = global.robot_manager
    self.store_manager = global.store_manager
    self.desk_message = global.desk_message
    self.banker_manager = global.banker_manager
    self.bairen_desk = global.bairen_desk

	self.server_id = self.room_config:getServerId()
 	self.table_id = self.room_config:getTableId()
 	self.table_type = self.room_config:getTableType()
 	self.table_gid = self.room_config:getTableGid()
 	self.game_type = self.room_config:getGameType()
 	self.table_pattern = self.room_config:getTablePattern()
 	return true
end

--跟网关agent绑定seesion监控 网关有关闭事件进行通知
function DeskBase:watchSession(uid, observing)
    local user = self.user_manager:getUser(uid)
    if not user then
        return 
    end
    local fd = user:getFD()
    if fd <= 0 or user:isRobot() then --机器人不需要用
        return
    end
    local gateway_id = fd >> 31
    local request
    if observing then
        request = 'observe_fd'
    else
        request = 'unobserve_fd'
    end        
    R().gateway(gateway_id):send('.watchdog','tablesvr',request, R().get_source(), fd, uid)
end

--结算后金币不足坐下条件，需要把他站起
function DeskBase:checkStandUpUser(uid)
    local user = self.user_manager:getUserInfo(uid)
    if not user or not user:isSeated() then 
        return 
    end
    local sitdown_coin = self.room_config:getSitdownCoin()
    if user:getCoins() > sitdown_coin then --大于最小可坐下需要的金币，不用站起
         return 
    end    
    local seat_id = user:getSeatId()
    if self.room_config:isHundredGame() then 
        --百人场1，4是特殊位置
        if seat_id == 1 or seat_id == 4 then         
            return 
        end
    end
    self.user_manager:standUp(uid)
    --通知所有玩家
    self:sendToAllUser('table.NTF_STANDUP', {uid=uid, seat_id=seat_id})    
end

--百人场 个人可下注筹码列表
--bet_list_name 在bet_list.lua 中的配置名
function DeskBase:getCanBetList(bet_list_name, coins)
    --指定一个币值，取下出列表   
    local betting_list = {100,500,1000,10000,50000}
    local bet_list = self.room_config:getBetList(bet_list_name)
    if not bet_list then 
        return betting_list
    end        
    for _, v in pairs(bet_list) do
        local range = string.split(v.coins_range,'-')
        local min = tonumber(range[1])
        local max = tonumber(range[2])
        if coins > min and ( not max or coins < max) then 
            if type(v.bet_list) == "table" then 
                return v.bet_list            
            end
        end  
    end
    return betting_list

end

--玩家金币变化流水
function DeskBase:addPlayerWater(user, coins)    
    if not user or user:isRobot() then 
        return 
    end
    if coins == 0 then 
        return 
    end
    local uid = user:getUid()
    R().basesvr({key = uid}):send('.msg_handler','add_player_coins_water', uid, math_abs(coins))
end

--投入产出op
function DeskBase:sendSummary(uid, bet_coins, produce, win_coins, free)
    local user = self.user_manager:getUser(uid)
    if not user or user:isRobot() then 
        return 
    end
    local data = {
        op = "user_summary",
        uid = uid,
        table_type = self.table_type,      
        win_lose = win_coins, --在玩游戏内产生的输赢（
        free = free, --玩游戏交上的台费
        bet_coins = bet_coins, --投注(当局下注分数
        produce = produce, --产出
    }
    dbglog("_______user_summary_____",  data)
    billlog(data) 
end

--输赢流水(百人场)
--win_coins 不算台费
function DeskBase:winLoseWater(user, bet_coins, win_coins, free)   
    if not user then
        return 
    end    
    local uid = user:getUid()
    free = free or 0
    if user:isRobot() then 
        -- if bet_coins > 0 then 
        --     --个人流水（用于vip升级
        --     R().basesvr({key=uid}):send('.msg_handler','add_person_water', uid, bet_coins, true)
        -- end
        return 
    end
    
    local str_date = os.date("%Y%m%d%H%M%S")    
    if bet_coins > 0 then 
        billlog({ op   = "water_history",  
            table_gid  = str_date .. "_" .. self.table_id,
            table_type = self.table_type,
            uid        = uid,
            value      = bet_coins,
            is_robot   = false,
            r          = constant.WATER_TYPE.WATER_BET
        })
        --个人流水（用于vip升级
        R().basesvr({key=uid}):send('.msg_handler','add_person_water', uid, bet_coins,user:isRobot())
    end

    if win_coins > 0 then
        --今日赢钱
        R().basesvr({key=uid}):send('.msg_handler', 'add_today_win_coins', uid, win_coins)        
    end
    R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,win_coins - free)
    user:addWinLose(win_coins - free) --离开桌子时用到
    user:addProduce(win_coins + bet_coins) --产出
    --今日游戏次数
    R().basesvr({key=uid}):send('.msg_handler','add_play_count', uid, 1)

    -- self:realTimeWinLose(user)
end

--输赢流水(红包扫雷)
--win_coins 不算台费
function DeskBase:winLoseWaterHBSL(user, water_coins, win_coins, free,hb_coins)   
    if not user then
        return 
    end    
    local uid = user:getUid()
    free = free or 0
    if user:isRobot() then 
        -- if water_coins > 0 then 
        --     --个人流水（用于vip升级
        --     R().basesvr({key=uid}):send('.msg_handler','add_person_water', uid, water_coins, true)
        -- end
        return 
    end
    
    local str_date = os.date("%Y%m%d%H%M%S")    
    if water_coins > 0 then 
        billlog({ op   = "water_history",  
            table_gid  = str_date .. "_" .. self.table_id,
            table_type = self.table_type,
            uid        = uid,
            value      = water_coins,
            is_robot   = false,
            r          = constant.WATER_TYPE.WATER_BET
        })
        --个人流水（用于vip升级
        R().basesvr({key=uid}):send('.msg_handler','add_person_water', uid, water_coins,user:isRobot())
    end

    if win_coins > 0 then
        --今日赢钱
        R().basesvr({key=uid}):send('.msg_handler', 'add_today_win_coins', uid, win_coins)        
    end
    R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,win_coins - free)
    user:addWinLose(win_coins - free) --离开桌子时用到
   -- user:addProduce(win_coins + hb_coins) --产出
    --今日游戏次数
    R().basesvr({key=uid}):send('.msg_handler','add_play_count', uid, 1)

    -- self:realTimeWinLose(user)
end

--玩这实时输赢op
function DeskBase:realTimeWinLose(user, leave_time)
    local uid = user:getUid()
    local table_gid = user:getEnterTime() .. "_" .. self.table_id .."_"..uid
    leave_time = leave_time or 0  --真正离开游戏了  
    if not user:getBeted() and user:getWinLose() == 0 and user:getFree() == 0 and user:getEnterCoins() == user:getCoins() then 
        --没产生流水就不记录了
        return
    end
    local data = {
        op = "user_leave_game",
        uid = uid,
        table_gid = table_gid, --唯一标记
        table_type = self.table_type,
        name = user:getName(),        
        enter_coins = user:getEnterCoins(), --进入时身上金币
        enter_safe_coins = user:getEnterSafeCoins(), --进入时保险箱金币 
        enter_time = user:getEnterTime(), --进入时间
        leave_time = leave_time, --离开时间
        leave_coins = user:getCoins(), --离开时身上金币
        leave_safe_coins = user:getSafeBox(), --离开时保险箱金币
        win_lose = user:getWinLose(), --在玩游戏内产生的输赢（
        free = user:getFree(), --玩游戏交上的台费
        bet_coins = user:getCurBet(), --投注(当局下注分数
        produce = user:getProduce(), --产出
    }
    dbglog("_______user_leave_game_____",  data)
    billlog(data)


end

--踢玩家出桌子
function DeskBase:kickUser(uid)
    local user = self.user_manager:getUserInfo(uid)
    if not user then 
        return 
    end    
    --reason原因 0离线 1走人 2换桌 3输钱达上限  4连续五局未下注离开 
    self:sendToUser(uid, 'table.NTF_LEAVE', {uid = uid, reason = 4, room_name = self.room_config:getRoomName()})    
    self:watchSession(uid, false) --跟网关agent绑定seesion监控
    if user:isSeated() then --有座位 
        --通知玩家有人离开
        -- self:sendToAllUser('table.NTF_LEAVE', {uid = uid, reason = 4, room_name = self.room_config:getRoomName()})
        self:sendToOther('table.NTF_STANDUP', uid, {uid = uid, seat_id = user:getSeatId()})
    end    
    self:sendUserLeave(uid)
    self.user_manager:removeUser(uid) 

    --通知分配服务器更新桌子状态
    self:ntMatchsvrTableStats()
    if user:isPlayer() then
        R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid, self.game_type, user:getInitCoins())
        R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})  
    end
end

--对局广播
function DeskBase:sendRealHorseMessage(uid, result_coins, broadcast_id)
    local user = self.user_manager:getUserInfo(uid)
    if not user then 
        return 
    end    
    local room_data = self.room_config:getRoomData()
    local exinfo = cjson.encode({game_type = self.room_config:getGameType()})
    if user:isPlayer() and result_coins > 0 then
        R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',broadcast_id,
        {name = user:getName(),coin = result_coins,vip_level = user:getVipLevel()})

        R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.GUIDE_BROAD,
        {vip_level = user:getVipLevel(),name = user:getName(),game_name = room_data.name or '',coin = result_coins,exinfo = exinfo})
    end
end


return DeskBase